﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Flame.Dlr;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Flame.Controls
{
    public class InOutControlEventArgs : EventArgs
    {
        internal InOutControl InOutControl { get; private set; }

        public InOutControlEventArgs(InOutControl inOutControl)
        {
            InOutControl = inOutControl;
        }
    }
    public class KeyDownBubbleEventArgs : EventArgs
    {
        public InOutControl InOutControl { get; private set; }
        public KeyEventArgs KeyEventArgs { get; private set; }
        public bool Handled { get; set; }

        public KeyDownBubbleEventArgs(InOutControl inOutControl, KeyEventArgs keyEventArgs)
        {
            Handled = false;
            InOutControl = inOutControl;
            KeyEventArgs = keyEventArgs;
        }
    }
    public partial class InOutControl : UserControl
    {
        public IOutput Output { get; private set; }
        public ATextInput Input { get; private set; }
        Panel _panelIn, _panelOut;

        public Result Result { get; private set; }


        public event EventHandler OnMoveCaretOnScreen;
        public event EventHandler OnChangeSize;
        public event EventHandler<InOutControlEventArgs> OnGotFocusChanged;
        public event EventHandler<InOutControlEventArgs> AskForFocusToNext;
        public event EventHandler<InOutControlEventArgs> AskForFocusToPrevious;
        public event EventHandler<KeyDownBubbleEventArgs> KeyDownBubble;
        public event EventHandler<LanguageChangedEventArgs> OnLanguageChanged;

        public event EventHandler<MouseEventArgs> MouseWheelFromChilds;

        public event EventHandler<EventArgs> OnCompile;

        public void ChangeInPanelHeight()
        {
            _panelIn.Height = Input.ContentHeight;
            Height = _panelIn.Height + _panelOut.Height;
            _panelOut.Location = new Point(_panelOut.Location.X, _panelIn.Height);

            //_panelOut.MouseWheel += (sender, e) => { if (MouseWheelFromChilds != null) MouseWheelFromChilds(sender, e); };
        }


        public bool AutoStart { get { return Input.AutoStart; } set { Input.AutoStart = (value); } }
        public Type Language { get { return Input.Language; } set { Input.Language = (value); } }

        void changeOutPanelHeight(int h)
        {
            _panelOut.Height = h;
            Height = _panelIn.Height + _panelOut.Height;
        }

        public InOutControl(ATextInput input, IOutput output)
        {
            InitializeComponent();

            Result = null;

            Input = input;
            Output = output;

            _panelIn = new Panel();
            _panelOut = new Panel();

            Controls.Add(_panelIn);
            Controls.Add(_panelOut);

            input.SetParent(_panelIn);
            Output.SetParent(_panelOut);

            Input.MouseWheelFromChilds += (s, e) => { if (MouseWheelFromChilds != null) MouseWheelFromChilds(s, e); };
            Input.OnMoveCaretOnScreen += (sender, e) => { if (OnMoveCaretOnScreen != null) OnMoveCaretOnScreen(sender, e); };

            Input.OnLanguageChanged += (s, e) => { if (OnLanguageChanged != null) OnLanguageChanged(this, e); };

            Input.OnCompile += (object s, CompilerResultEventArgs e) =>
            {
                Result = e.CompilerResult;
                TextCompilerResult textCompilerResult = Output.Set(Result);
                if (OnCompile != null) OnCompile(this, new EventArgs());
                changeOutPanelHeight(textCompilerResult.Height);
            };
            Input.OnResizeHeight += (s, e) =>
            {
                ChangeInPanelHeight();
                OnChangeSize(s, e);
            };
            Input.GotFocus += (object sender, EventArgs e) =>
            {
                OnGotFocusChanged(sender, new InOutControlEventArgs( this));
            };

            Input.AskForFocusToNext += (s, e) =>
            {
                AskForFocusToNext(s, new InOutControlEventArgs(this));
            };
            Input.AskForFocusToPrevious += (s, e) =>
            {
                AskForFocusToPrevious(s, new InOutControlEventArgs(this));
            };
            Input.KeyDown += (object sender, KeyEventArgs e) =>
            {
                var kdb = new KeyDownBubbleEventArgs(this, e);
                if(KeyDownBubble != null)
                    KeyDownBubble(this, kdb);
                e.SuppressKeyPress = e.SuppressKeyPress || kdb.Handled;
            };

            SaveState();
           
        }

        public void RefreshHeights()
        {
            _panelIn.Height = Input.ContentHeight;
            _panelOut.Height = Output.ContentHeight;
        }

        private void InOutControl_Load(object sender, EventArgs e)
        {
            _panelIn.Location = new Point(0, 0);
            _panelIn.Size = Size;
            _panelOut.Size = new Size(Size.Width, 0);
            _panelOut.Location = new Point(0, Size.Height);

            ChangeInPanelHeight();
            changeOutPanelHeight(0);
        }

        private void InOutControl_Resize(object sender, EventArgs e)
        {
            _panelIn.Width = Width;
            _panelOut.Width = Width;
        }

        public bool IsInputEmpty { get { return Input.Text == ""; } }
        internal void SetInputCusorBegin() { Input.CurrentPos = 0; }
        internal void SetInputCusorEnd() { Input.CurrentPos = Input.Text.Length; }

        Script _inputTextTemp;
        public bool HasStateChanged { get { return !_inputTextTemp.Equals(new Cell(InputLanguage, InputText, InputAutoStart)); } }
        public void SaveState() { _inputTextTemp = new Cell(InputLanguage, InputText, InputAutoStart); }

        public string InputText { get { return Input.Text; } set { Input.Text = value;  } }
        internal int InputCurrentPos { get { return Input.CurrentPos; } set { Input.CurrentPos = value; } }

        public bool InputFocused { get { return Input.Focused; } }
        internal void InputFocus() { Input.Focus(); }
        public bool InputAutoStart { get { return Input.AutoStart; } set { Input.AutoStart = value; } }
        public int InputCaretOnScreenPosY { get { return Input.CaretOnScreenPosY; } }
        public Type InputLanguage { get { return Input.Language; } set { Input.Language = value; } }

        internal void CompileInput()
        {
            Input.Compile();
        }

        //public ICompiler InputCurrentCompilerEngine { get { return _input.CurrentCompilerEngine; } }

        internal void Clear()
        {
            Output.Clear();
            changeOutPanelHeight(0);
        }
    }
}
